# ~*~ coding: utf-8 ~*~
import uuid
import time
import random
import string
import hashlib
import os
from datetime import datetime
from itsdangerous import TimedJSONWebSignatureSerializer, JSONWebSignatureSerializer, \
    BadSignature, SignatureExpired
from flask import request

from apps.config import ConfigManager

CONFIG = ConfigManager.load_user_config()


def date_str_to_obj(value):
    if value:
        return datetime.strptime(value, '%Y-%m-%d').date()


def date_obj_to_str(value):
    if value:
        return value.strftime('%Y-%m-%d')


def datetime_str_to_obj(value):
    if value:
        return datetime.strptime(value, "%Y-%m-%d %H:%M:%S")


def datetime_obj_to_str(value):
    if value:
        return value.strftime("%Y-%m-%d %H:%M:%S")


def timestamp_obj_to_str(value):
    if value:
        return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(value))


def timestamp_obj_to_datetime(value):
    if value:
        return datetime.strptime(timestamp_obj_to_str(value), '%Y-%m-%d %H:%M:%S')


def date_str_to_timestamp(value):
    if value:
        return time.mktime(time.strptime(value, '%Y-%m-%d'))


def datetime_str_to_timestamp(value):
    if value:
        return time.mktime(time.strptime(value, '%Y-%m-%d %H:%M:%S'))


def fill_date_to_timestamp(flag, value):
    if flag and value:
        if flag == 'start':
            return datetime_str_to_timestamp(value.strip() + " 00:00:00")
        elif flag == 'end':
            return datetime_str_to_timestamp(value.strip() + " 23:59:59")


class Singleton(type):
    def __init__(cls, *args, **kwargs):
        cls.__instance = None
        super().__init__(*args, **kwargs)

    def __call__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super().__call__(*args, **kwargs)
            return cls.__instance
        else:
            return cls.__instance


class Signer(metaclass=Singleton):
    """用来加密,解密,和基于时间戳的方式验证token"""
    def __init__(self, secret_key=None):
        self.secret_key = secret_key

    def sign(self, value):
        s = JSONWebSignatureSerializer(self.secret_key, algorithm_name='HS256')
        return s.dumps(value).decode()

    def unsign(self, value):
        if value is None:
            return value
        s = JSONWebSignatureSerializer(self.secret_key, algorithm_name='HS256')
        try:
            return s.loads(value)
        except BadSignature:
            return {}

    def sign_t(self, value, expires_in=3600):
        s = TimedJSONWebSignatureSerializer(self.secret_key, expires_in=expires_in)
        return str(s.dumps(value), encoding="utf8")

    def unsign_t(self, value):
        s = TimedJSONWebSignatureSerializer(self.secret_key)
        try:
            return s.loads(value)
        except (BadSignature, SignatureExpired):
            return {}


def get_signer():
    signer = Signer(CONFIG.SECRET_KEY)
    return signer


def generate_uuid():
    return uuid.uuid4().__str__()


def short_uuid():
    return generate_uuid().split('-')[0]


def encrypt_password(password, salt=None):
    from passlib.hash import sha512_crypt
    if password:
        return sha512_crypt.using(rounds=5000).hash(password, salt=salt)
    return None


def generate_password(len=16):
    """生成n个长度为len的随机序列码"""
    random.seed()
    chars = string.ascii_letters + string.digits
    return ''.join([random.choice(chars) for _ in range(len)])


def md5(s):
    m = hashlib.md5()
    b = s.encode(encoding='utf-8')
    m.update(b)
    return m.hexdigest()


def md5_token(str):
    obj = hashlib.md5()
    obj.update(str.encode())
    return obj.hexdigest()[0:15]


def list2dict(ls, is_join=True):
    d = {}
    for l in ls:
        if not d.get(l[0]):
            d[l[0]] = [l[1]]
        else:
            d[l[0]].append(l[1])

    if is_join:
        for k, v in d.items():
            v = [str(i) for i in v]
            d[k] = ', '.join(v)
    return d


def gen_datetime_path():
    year = time.strftime('%Y')
    month = time.strftime('%m')
    day = time.strftime('%d')
    path = os.path.join(year, '{}{}'.format(month, day))
    return path


def get_remote_address():
    ip = request.headers.get('X-Forwarded-For')
    if not ip:
        ip = request.remote_addr
    if not ip:
        ip = '-'
    return ip

